<!doctype html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="kniost, NexT" />





  <link rel="alternate" href="/atom.xml" title="结网之路" type="application/atom+xml" />




  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0" />






<meta name="description" content="kniost 的成长与疑惑">
<meta property="og:type" content="website">
<meta property="og:title" content="结网之路">
<meta property="og:url" content="https://kniost.github.io/page/3/index.html">
<meta property="og:site_name" content="结网之路">
<meta property="og:description" content="kniost 的成长与疑惑">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="结网之路">
<meta name="twitter:description" content="kniost 的成长与疑惑">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    sidebar: {"position":"right","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://kniost.github.io/page/3/"/>





  <title> 结网之路 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  














  
  
    
  

  <div class="container one-collumn sidebar-position-right 
   page-home 
 ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">结网之路</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">临渊羡鱼，不如退而结网</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-21-cj0ajvoul000f1js6d87atmkh/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-21-cj0ajvoul000f1js6d87atmkh/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（十）—— 第10章 使用 fragment argument
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-21T11:07:10+08:00">
                2016-10-21
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-21-cj0ajvoul000f1js6d87atmkh/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-21-cj0ajvoul000f1js6d87atmkh/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要介绍了如何使用 fragment 的 arguments 来传递信息<br>GitHub 地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/293ebe3320fc6201384132b247dffce9d9f40654" target="_blank" rel="external">完成第十章</a></p>
</blockquote>
<h1 id="1-从-fragment-中启动-activity"><a href="#1-从-fragment-中启动-activity" class="headerlink" title="1. 从 fragment 中启动 activity"></a>1. 从 fragment 中启动 activity</h1><h2 id="1-1-直接启动"><a href="#1-1-直接启动" class="headerlink" title="1.1 直接启动"></a>1.1 直接启动</h2><p>从 fragment 中直接启动 acitivity 的方法一般如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Intent intent = <span class="keyword">new</span> Intent(getActivity(), TargetActivity.class);</div><div class="line">startActivity(intent);</div></pre></td></tr></table></figure>
<p>Fragment 中也带有 startActivity()方法，其中 Intent 构造方法需要的 Context 对象可以通过 getActivity() 方法获得。</p>
<h2 id="1-2-附加-extra-信息"><a href="#1-2-附加-extra-信息" class="headerlink" title="1.2 附加 extra 信息"></a>1.2 附加 extra 信息</h2><p>一般来说，为了保证类之间的独立，启动一个 activity 的 intent 及其需要的参数应该写在目标 activity 中，对于 fragment 同样如此。</p>
<p>对需要启动的目标 activity 可以如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//先定义一个 key 以便识别</span></div><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String EXTRA_KEY = <span class="string">"com.kniost.appname.activity_name"</span>;</div><div class="line"></div><div class="line"><span class="comment">//然后定义一个获取专用的 Intent 的静态公有方法</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Intent <span class="title">newIntent</span><span class="params">(Context context, Object data)</span> </span>&#123;</div><div class="line">	Intent intent = <span class="keyword">new</span> Intent(context, TargetActivity.class);</div><div class="line">	intent.putExtra(EXTRA_KEY, data);</div><div class="line">	<span class="keyword">return</span> intent;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>在需要的时候调用这个方法得到 Intent 并启动即可。</p>
<h2 id="1-3-获取-extra-信息"><a href="#1-3-获取-extra-信息" class="headerlink" title="1.3 获取 extra 信息"></a>1.3 获取 extra 信息</h2><p>activity 可以通过 getIntent().getExtra() 方法直接获取信息，然而真正需要信息的是 fragment。fragment 可不能用 intent 启动。</p>
<p>在 fragment 中有两种方法可以获取信息：</p>
<ul>
<li>一是从 activity 的 extra 中获取信息。这种方法比较简单，但是不推荐，因为它破怪了 fragment 的封装性，不利于解耦（在一个类中用到另一个类的变量），不便于复用。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Object data = (Object) getActivity().getIntent().getSerializable(EXTRA_KEY);</div></pre></td></tr></table></figure>
<ul>
<li><p>第二个就是比较好的做法，那就是将数据存放在 fragment 的 argument bundle 中，这样无需托管的 activity 的 intent 内指定 extra 的存在，fragment 本身就能获取自己所需的 extra 数据。</p>
<p>  和给一个 activity 传递 extra 信息类似，一般也会在目标fragment 中添加一个公有的静态方法 newInstance()，参数则是需要的 extra 信息</p>
</li>
</ul>
<pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//首先也要定义一个 key 用于获取数据</span></div><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String ARG_EXTRA_KEY = <span class="string">"data_I_need"</span>;</div><div class="line">……</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> TargetFragment <span class="title">newInstance</span><span class="params">(Object data)</span> </span>&#123;</div><div class="line">	Bundle args = <span class="keyword">new</span> Bundle();</div><div class="line">	args.putSerializable(ARG_EXTRA_KEY, data);</div><div class="line">	TargetFragment fragment = <span class="keyword">new</span> TargetFragment();</div><div class="line">	fragment.setArguments(args);</div><div class="line">	<span class="keyword">return</span> fragment;</div><div class="line">&#125;</div></pre></td></tr></table></figure>

这样，在托管的 activity 中新建 TargetFragment 类的时候只要调用 TargetFragment.newInstance(Object data) 来获取实例即可。

在 fragment 里获取 argument 的方法比较简单，直接调用 getArguments().getX() 方法即可，其中 X 表示可以从 Bundle 中获取的类型，Serializable 是比较常用的传递复杂参数的方法。
</code></pre><h1 id="2-刷新显示列表项"><a href="#2-刷新显示列表项" class="headerlink" title="2. 刷新显示列表项"></a>2. 刷新显示列表项</h1><p>由于书上的例子中使用的是单例，也就是说对于 Adapter 和 Fragment 来说使用的数据都是指向同一地址的，只要在某处修改了，所有使用该数据的地方实际都改变了。这样的话，修改数据之后只需要使用 RecyclerView.Adatper 的方法 notifyDataSetChanged() 即可刷新 RecyclerView 了。</p>
<h1 id="3-挑战练习：实现高效的-RecyclerView-刷新"><a href="#3-挑战练习：实现高效的-RecyclerView-刷新" class="headerlink" title="3. 挑战练习：实现高效的 RecyclerView 刷新"></a>3. 挑战练习：实现高效的 RecyclerView 刷新</h1><p>使用 notifyItemChanged(int position) 方法可以高效地刷新单个被修改的 ViewHolder。</p>
<p>对于本书的这个问题，有特殊的做法。因为这个 RecyclerView 和 fragment 是写在一个类中的，而且一次只会有一个 ViewHolder 被改变，所以可以通过读写同一个成员变量来判断修改的 item 的位置。 </p>
<p>以下是具体解决方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//CrimeListFragment.java</span></div><div class="line"></div><div class="line"><span class="keyword">private</span> <span class="keyword">int</span> positionClicked;</div></pre></td></tr></table></figure>
<p>然后在 ViewHolder 的构造函数建立 Listener 的时候用 getAdapterPosition() 方法记录下被点击的 ViewHolder 的位置</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</div><div class="line">	Intent intent = CrimeActivity.newInent(getActivity(), mCrime.getId());</div><div class="line">	positionClicked = getAdapterPosition();</div><div class="line">	startActivity(intent);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>最后在 updateUI() 函数中直接调用 mAdapter.notifyItemChanged(positionClicked);</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (mAdapter == <span class="keyword">null</span>) &#123;</div><div class="line">   mAdapter = <span class="keyword">new</span> CrimeAdapter(crimes);</div><div class="line">   mCrimeRecyclerView.setAdapter(mAdapter);</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">   mAdapter.notifyItemChanged(positionClicked);</div><div class="line">&#125;</div></pre></td></tr></table></figure>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-21-cj0ajvow5002q1js6m3pj66l0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-21-cj0ajvow5002q1js6m3pj66l0/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（九）—— 第9章 使用 RecyclerView 显示列表
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-21T11:02:10+08:00">
                2016-10-21
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-21-cj0ajvow5002q1js6m3pj66l0/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-21-cj0ajvow5002q1js6m3pj66l0/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要讲述了 RecyclerView 的基础使用，单例设计模式以及通过抽象的统一的 activity 来托管 fragment（以减少重复代码量）。</p>
<p>GitHub 地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/42ccc8c20dbe84c17a53691ec2dc905ced4fdff9" target="_blank" rel="external">完成第九章</a></p>
</blockquote>
<h1 id="1-单例-SingleInstance"><a href="#1-单例-SingleInstance" class="headerlink" title="1. 单例(SingleInstance)"></a>1. 单例(SingleInstance)</h1><p>单例是特殊的 JAVA 类，在创建实例的时候，一个单例类仅允许创建一个实例。应用能在内存里多久，单例就能存在多久，因此将对象列表保存在单例里的话，就能随时获取到数据，而不用管 activity 和 fragment 的生命周期怎么变化。不过当应用被从内存里移除的时候，单例对象就不复存在了。</p>
<p>要创建单例，需要创建一个带有私有构造方法及 get() 方法的类，如果实例已经存在了，get() 方法就直接返回它，如果还不存在，就需要调用构造方法创建它。书上的代码是这样的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CrimeLab</span> </span>&#123;</div><div class="line">	<span class="comment">//下面这个静态对象只会创建一次</span></div><div class="line">	<span class="keyword">private</span> <span class="keyword">static</span> CrimeLab sCrimeLab;</div><div class="line">	</div><div class="line">	<span class="keyword">private</span> List&lt;Crime&gt; mCrimes;</div><div class="line">	</div><div class="line">	<span class="comment">//程序的其他部分需要使用时，调用下列方法，当第一次使用的时候创建这个对象，如果不是第一次使用的时候就直接返回静态对象。</span></div><div class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CrimeLab <span class="title">get</span><span class="params">(Context context)</span> </span>&#123;</div><div class="line">		<span class="keyword">if</span> (sCrimeLab == <span class="keyword">null</span>) &#123;</div><div class="line">			sCrimeLab = <span class="keyword">new</span> CrimeLab(context);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> sCrimeLab;</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	<span class="comment">//私有的构造方法，只在 get 方法中使用</span></div><div class="line">	<span class="function"><span class="keyword">private</span> <span class="title">CrimeLab</span><span class="params">(Context context)</span> </span>&#123;</div><div class="line">		mCrimes = <span class="keyword">new</span> ArrayList&lt;&gt;();</div><div class="line">		<span class="comment">//初始化数据的语句</span></div><div class="line">		………………</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	<span class="comment">//由于对象只创建了一次，故而数据只有一份</span></div><div class="line">	<span class="function"><span class="keyword">public</span> List&lt;Crime&gt; <span class="title">getCrimes</span><span class="params">()</span> </span>&#123;</div><div class="line">		<span class="keyword">return</span> mCrimes;</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">public</span> Crime <span class="title">getCrime</span><span class="params">(UUID id)</span> </span>&#123;</div><div class="line">		<span class="keyword">for</span> (Crime crime : mCrimes) &#123;</div><div class="line">			<span class="keyword">if</span> (crime.getId().equals(id)) &#123;</div><div class="line">				<span class="keyword">return</span> crime;</div><div class="line">			&#125;</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><strong>单例能方便地控制模型层对象，由一个单例类来控制数据，所有的修改都由它处理，会使数据的一致性控制更加简便。</strong></p>
<p>但是万事总有缺点，</p>
<ul>
<li>首先，单例无法做到持久的存储，应用的内存被回收时，单例就不复存在了。</li>
<li>其次，单例还不利于单元测试。</li>
<li>最后，单例还容易被滥用，需要注意的是有充足的理由时才使用单例模式存储共享数据。</li>
</ul>
<h1 id="2-使用抽象-activity-托管-fragment"><a href="#2-使用抽象-activity-托管-fragment" class="headerlink" title="2. 使用抽象 activity 托管 fragment"></a>2. 使用抽象 activity 托管 fragment</h1><blockquote>
<p>由于书中大部分 FragmentActivity 的是类似的，所以可以直接创建一个抽象的类用于被继承，简化代码。</p>
</blockquote>
<p>回忆一下使用 fragment 的步骤：</p>
<ol>
<li>在托管的 activity 的 onCreate() 方法中新建一个 FragmentManager 对象（getSupportFragmentManager() 方法或者 getFragmentManager() 方法）。</li>
<li>使用该对象的 findFragmentById() 方法找到放置 fragment 的位置。</li>
<li>如果 fragment 没有建立，就新建一个 fragment 对象，并使用 FragmentManager 对象的 beginTransaction().add().commit() 的连续方法将 fragment 事务提交到队列中</li>
</ol>
<p>在这其中，只有新建 fragment 对象是与具体 fragment 有关的，那么我们可以将其写成一个抽象的函数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> Fragment <span class="title">createFragment</span><span class="params">()</span></span>;</div></pre></td></tr></table></figure>
<h1 id="3-RecyclerView-Adapter-和-ViewHolder"><a href="#3-RecyclerView-Adapter-和-ViewHolder" class="headerlink" title="3. RecyclerView, Adapter 和 ViewHolder"></a>3. RecyclerView, Adapter 和 ViewHolder</h1><blockquote>
<p>对于一个列表，之前有 ListView，网格有 GridView，但要实现更加复杂的布局和功能，比如瀑布流的时候，就有些力不从心了。RecyclerView 是 Google 推出 Android 5.0 时一并推出的控件，其具有强大的功能和高度的解耦，有助于开发者实现更加多变具有拓展能力的布局。</p>
</blockquote>
<h2 id="3-1-RecyclerView-简介及工作原理"><a href="#3-1-RecyclerView-简介及工作原理" class="headerlink" title="3.1 RecyclerView 简介及工作原理"></a>3.1 RecyclerView 简介及工作原理</h2><p>要使用 RecyclerView 显示视图，需要三样东西，即RecyclerView，Adapter， ViewHolder，它们的任务各不相同：</p>
<ul>
<li>RecyclerView 是视图层对象，负责回收和定位屏幕上的 ViewHolder</li>
<li>ViewHolder 只负责容纳 View 视图</li>
<li>Adapter 是控制器对象，负责创建必要的 ViewHolder，从模型层获取数据并与 ViewHolder 绑定，然后提供给 RecyclerView 显示</li>
</ul>
<p>RecyclerView 需要显示视图对象时，就会去找它的 Adapter，然后会有如下调用。</p>
<ol>
<li>首先，调用 Adapter 的 getItemCount() 方法，RecyclerView 询问数组列表中包含多少个对象。</li>
<li>接着，调用 Adapter 的 createViewHolder(ViewGroup, int) 方法创建 ViewHolder 以及 ViewHolder 要显示的视图。</li>
<li>最后，RecyclerView 会传入 ViewHolder 及其位置，调用 onBindViewHolder(ViewHolder, int) 方法。Adapter 会找到目标位置的数据并用数据填充到 ViewHolder 的视图上。</li>
</ol>
<p>过程图示如下：<br><img src="http://img.blog.csdn.net/20161109154759638" alt="这里写图片描述"></p>
<blockquote>
<p>需要注意的是，相对于 onBindViewHolder(ViewHolder, int) 方法，createViewHolder(ViewGroup, int) 方法的调用并不频繁。一旦创建了够用的 ViewHolder，RecyclerVIew 就会停止调用 createViewHolder() 方法，然后通过回收旧的 ViewHolder 来节约时间和内存。</p>
</blockquote>
<h2 id="3-2-使用-RecyclerView"><a href="#3-2-使用-RecyclerView" class="headerlink" title="3.2 使用 RecyclerView"></a>3.2 使用 RecyclerView</h2><p>介绍了 RecyclerView 的各种细节，我们来看看它具体怎么使用吧。</p>
<h3 id="3-2-1-添加-RecyclerView-依赖库"><a href="#3-2-1-添加-RecyclerView-依赖库" class="headerlink" title="3.2.1 添加 RecyclerView 依赖库"></a>3.2.1 添加 RecyclerView 依赖库</h3><p>在 File - Project Structure 菜单项，选择 app 模块，然后单击 Dependencies 选项页，单击加号，找到并添加 recyclerview-v7 支持库。</p>
<h3 id="3-2-2-在布局文件中使用-RecyclerView-并在-JAVA-代码中声明"><a href="#3-2-2-在布局文件中使用-RecyclerView-并在-JAVA-代码中声明" class="headerlink" title="3.2.2 在布局文件中使用 RecyclerView 并在 JAVA 代码中声明"></a>3.2.2 在布局文件中使用 RecyclerView 并在 JAVA 代码中声明</h3><p>示例 JAVA 代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);</div><div class="line">mCrimeRecyclerView.setLayoutManager(<span class="keyword">new</span> LinearLayoutManager(getActivity()));</div></pre></td></tr></table></figure>
<p>RecyclerView 视图创建完成后，就立即转交给了 LayoutManager 对象。LayoutManager 实际上负责定位列表项和定义屏幕滚动行为，因此如果没有 LayoutManger 的支持，不仅 RecyclerView 无法工作，还会导致应用崩溃。在示例中使用的 LinearLayoutManager 是以竖直列表的方式展示列表项，内置的还有GridLayoutManager ，还有很多第三方的库可以使用。</p>
<h3 id="3-2-3-实现-Adapter-和-ViewHolder"><a href="#3-2-3-实现-Adapter-和-ViewHolder" class="headerlink" title="3.2.3 实现 Adapter 和 ViewHolder"></a>3.2.3 实现 Adapter 和 ViewHolder</h3><p>ViewHolder 需要做的事情很简单，就是将自定义的 view 中的组件找出来并绑定在这个 ViewHolder 的成员变量上。</p>
<p>比如定义了一个有标题和图片的 item，那么这个 Holder 可以这么写：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ItemHolder</span> <span class="keyword">extends</span> <span class="title">RecyclerView</span>.<span class="title">ViewHolder</span> </span>&#123;</div><div class="line">	</div><div class="line">	<span class="keyword">public</span> TextView mTitle;</div><div class="line">	<span class="keyword">public</span> ImageView mImg;</div><div class="line">	</div><div class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ItemHolder</span><span class="params">(View itemView)</span> </span>&#123;</div><div class="line">		<span class="keyword">super</span>(itemView);</div><div class="line"></div><div class="line">		mTitle = (TextView) itemView.findViewById(R.id.tv_item_title);</div><div class="line">		mImg = (ImageView) itemView.findViewById(R.id.iv_item_img);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<blockquote>
<p>如果有监听器的话，也可以写在构造函数中</p>
</blockquote>
<p>对于 Adapter 来说，要做的事就更多了，我来一一梳理：</p>
<ul>
<li><p><strong>从模型层获取数据</strong><br> 一般在 Adapter 内部声明一个数据模型的成员变量，在 Adapter 的构造函数中进行初始化</p>
</li>
<li><p><strong>重写 ViewHolder 这个父类的三个方法</strong></p>
<ul>
<li><p><code>onCreateViewHolder(ViewGroup parent, int viewType)</code><br>每当 RecyclerView 需要新的 View 视图来显示列表项的时候就会调用这个方法。在这其中，我们创建 View 视图，然后封装到 ViewHolder 中，此时并不需要向视图加载数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//一个典型的 onCreateViewHolder 方法的内部</span></div><div class="line">LayoutInflater layoutInflater = LayoutInflater.from(getActivity());</div><div class="line">View view = layoutInflater.inflate(R.layout.list_item, parent, <span class="keyword">false</span>);</div><div class="line"><span class="keyword">return</span> <span class="keyword">new</span> ItemHolder(view);</div></pre></td></tr></table></figure>
</li>
<li><p><code>onBindViewHolder(ItemHolder holder, int position)</code><br>这个方法负责将 ViewHolder 的 View 视图和模型层的数据绑定起来。拿到 ViewHolder 和列表项在数据集中的索引位置后，我们通过索引位置找到要显示的数据进行绑定。绑定完毕后，刷新显示 View 视图。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">//典型的 onBindViewHolder 方法内部</div><div class="line">Data data = mDataList.get(position); </div><div class="line">// 注意上面的 mDataList 就是在 Adatper 的构造函数中初始化的 Adapter 的成员变量</div><div class="line">holder.mTitle.setText(data.getTitle(position));</div><div class="line">holder.mImg.setImageResource(data.getImgRes(position));</div></pre></td></tr></table></figure>
</li>
<li><p><code>getItemCount()</code><br>返回要展示的数据的数量，一般是数据集的 size</p>
</li>
</ul>
</li>
</ul>
<p>到此一个基本的 Adapter 就创建完了，在主程序中声明并初始化 Adapter，调用 RecyclerView 的 setAdapter 方法即可显示出列表了~</p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-21-cj0ajvow2002n1js67lhbcn80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-21-cj0ajvow2002n1js67lhbcn80/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（八）—— 第8章 使用布局与组件创建用户界面
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-21T11:01:10+08:00">
                2016-10-21
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-21-cj0ajvow2002n1js67lhbcn80/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-21-cj0ajvow2002n1js67lhbcn80/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要介绍了一些进阶的界面设计知识，以及如何用图形化界面设计 UI （虽然不推荐日常使用，但是至少要知道，特别是在 Android Studio 2.2 推出之后，可以直接查看设计蓝图，更为直观并且容易调整细节）。</p>
<p>GitHub 地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/e6f879af23dfa599f09292d35b6a884647db93e8" target="_blank" rel="external">完成第八章，未完成挑战</a><br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/1c91e7688a9810dfb032b76bc4615ff8aa239816" target="_blank" rel="external">完成第八章的挑战</a></p>
</blockquote>
<h2 id="1-样式（style）-与-主题（theme）"><a href="#1-样式（style）-与-主题（theme）" class="headerlink" title="1. 样式（style） 与 主题（theme）"></a>1. 样式（style） 与 主题（theme）</h2><blockquote>
<p>为什么我们需要样式（style）？ 因为当界面有统一风格时，就不需要针对每一个控件单独写属性了，规定几种样式（style）即可。</p>
</blockquote>
<p>style 是 XML 资源文件，含有用来描述组件行为和外观的属性定义。例如，下面的样式能让其显示的文字大小大于一般的值。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">name</span>=<span class="string">"BigTextStyle"</span>&gt;</span><span class="xml"></span></div><div class="line">	<span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">"android:textSize"</span>&gt;</span>20sp<span class="tag">&lt;/<span class="name">item</span>&gt;</span></div><div class="line">	<span class="tag">&lt;<span class="name">item</span> <span class="attr">name</span>=<span class="string">"android:padding"</span>&gt;</span>3dp<span class="tag">&lt;/<span class="name">item</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">style</span>&gt;</span></div></pre></td></tr></table></figure>
<p>我们可以在 res/values/ 目录下的样式文件中写入自己需要的属性定义，然后再布局文件中以 <code>@style/my_own_style(file name)</code> 的形式引用</p>
<blockquote>
<p>什么是主题（theme）呢？主题是各种样式的集合，从结构上来说，主体本身也是一种样式资源，不过它的属性指向了其他样式资源</p>
</blockquote>
<p> <em>主题属性引用</em> 顾名思义就是将预定义的应用主题样式添加给指定组件，比如给 TextView 控件定义下面的属性：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">style="?android:listSeparatorTextViewStyle"</span>&gt;</span></div></pre></td></tr></table></figure>
<p>意味着告诉 Android 运行资源管理器：“在应用主题里找到名为 listSeparatorTextViewStyle 的属性。该属性指向其他样式资源，请将其资源的值放在这里。”</p>
<h2 id="2-margin-与-padding"><a href="#2-margin-与-padding" class="headerlink" title="2. margin 与 padding"></a>2. margin 与 padding</h2><p>Android 布局文件中的 margin 和 padding 跟 Web 编程的一样，具体定义如下：</p>
<ul>
<li>margin 指的是外边距，即指定视图组件之间的距离</li>
<li>padding 指的是内边距，即指定视图外边框与其内容间的距离</li>
</ul>
<p>两者之间区别如下图：<br><img src="http://img.blog.csdn.net/20161027171304182" alt="margin 和 padding"></p>
<h2 id="3-dp、sp-及屏幕像素密度"><a href="#3-dp、sp-及屏幕像素密度" class="headerlink" title="3. dp、sp 及屏幕像素密度"></a>3. dp、sp 及屏幕像素密度</h2><p>Android 使用密度修饰 drawable 目录（如 drawable-xhdpi）下的图像文件会自动适配不同像素密度的屏幕。那么问题来了，加入图像完成了自动适配，但是边距无法缩放适配，或者用户配置了大于默认值的文字大小，会出现什么意外呢？</p>
<p>为了解决这些可能的问题，Android 提供了密度无关的尺寸单位（density-independent dimension unit）。使用这种单位，可在不同屏幕密度的设备上获得同样的尺寸。无需进行麻烦的转换计算，应用运行时，Android 会自动将这种单位转换成像素单位。</p>
<h3 id="1-dp-dip-density-independent-pixel-密度无关像素"><a href="#1-dp-dip-density-independent-pixel-密度无关像素" class="headerlink" title="1. dp (dip, density-independent pixel) 密度无关像素"></a>1. dp (dip, density-independent pixel) 密度无关像素</h3><p>所谓密度无关，即和屏幕的像素密度没有关系。1dp 单位在设备的屏幕上总是等于 1/160 英寸。使用 dp 的好处是，无论屏幕密度如何，总能获得同样的尺寸。</p>
<blockquote>
<p>px = dp * (dpi / 160)</p>
</blockquote>
<p>其中，dpi 即等于我们常说的 ppi，计算公式即为</p>
<blockquote>
<p>ppi = sqrt(屏幕横向像素数的平方 + 屏幕纵向像素数的平方）/ 屏幕对角线英寸数</p>
</blockquote>
<p>那么常见的 mdpi， hdpi 是什么呢？对应关系如下图：<br><img src="http://img.blog.csdn.net/20161107141648322" alt="ppi 对应尺寸"></p>
<p>也就是说 160ppi 像素密度的屏幕，又叫 mdpi 的屏幕，程序中写的 1dp 在上面呈现的就是 1 像素（pixel，px）。</p>
<h3 id="2-sp-scale-independent-pixel-缩放无关像素"><a href="#2-sp-scale-independent-pixel-缩放无关像素" class="headerlink" title="2. sp (scale-independent pixel) 缩放无关像素"></a>2. sp (scale-independent pixel) 缩放无关像素</h3><p>这种像素也与屏幕无关，但是与设置有关，一般用来设置文本的大小。</p>
<h2 id="4-android-layout-weight-属性"><a href="#4-android-layout-weight-属性" class="headerlink" title="4. android:layout_weight 属性"></a>4. android:layout_weight 属性</h2><p>在 LinearLayout 中，有这样一个特殊属性，它能让你自由分配摆放部件后的空间，避免大量留白。它就是 android:layout_weight，这里的 weight 是权重的意思，也就是说，每个部件都有自己的权重，用于分配摆放部件后<strong>剩余的空间</strong>。也就是说，如果两个部件权重都是 1 时，它们平分摆放它们之后的剩余空间。</p>
<p>但是这样就会出现一个问题，由于分配的是剩余的空间，所以在两个部件 layout_width 属性不一致（wrap_content 不算一致）时，layout_weight 属性不能使部件平分整块屏幕。如果想要平分怎么办呢？把两个部件的 layout_width 都设为 0dp 再保持其 weight 相等，也就是把整块屏幕都当做剩余空间，就能平分整块屏幕了。</p>
<h2 id="5-挑战练习：日期格式化"><a href="#5-挑战练习：日期格式化" class="headerlink" title="5. 挑战练习：日期格式化"></a>5. 挑战练习：日期格式化</h2><p>我使用的是 SimpleDateFormat 类，它能通过字符串来直接格式化 Date 类型的数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">SimpleDateFormat sdf = <span class="keyword">new</span> SimpleDateFormat(<span class="string">"EEEE, MMM d, y"</span>, Locale.US);</div><div class="line">mDateButton = (Button) v.findViewById(R.id.crime_date);      mDateButton.setText(sdf.format(mCrime.getDate()));</div></pre></td></tr></table></figure>
          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-21-cj0ajvow1002k1js69bvl2wsr/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-21-cj0ajvow1002k1js69bvl2wsr/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（七）—— 第7章 UI fragment 与 fragment 管理器
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-21T10:59:10+08:00">
                2016-10-21
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-21-cj0ajvow1002k1js69bvl2wsr/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-21-cj0ajvow1002k1js69bvl2wsr/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章介绍了 fragment 的来由，activity 与 fragment 的关系，及其基础使用</p>
<p>GitHub 地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/0917ea242f26e72902e574860432fa7eb0bfaff8" target="_blank" rel="external">完成第七章</a></p>
</blockquote>
<h1 id="1-为何要使用-fragment"><a href="#1-为何要使用-fragment" class="headerlink" title="1. 为何要使用 fragment ?"></a>1. 为何要使用 fragment ?</h1><p>使用 fragment 而不是 activity 来管理应用UI，可以绕开 Android 系统 activity 使用规则的限制。</p>
<blockquote>
<p>fragment 是一种控制器对象， activity 可委派它完成一些任务，通常是管理 UI，可以是一整屏也可以是一部分， 管理 UI 的 fragment 又叫 UI fragment。它自己也有产生于布局文件的视图。 fragment 视图包含了用户可以交互的可视化 UI 元素。</p>
<p>利用 fragment，可以轻松实现选择不同的列表项就显示对应的明细视图， activity 用一个明细 fragment 替换另一个明细 fragment， 这样就可以避免销毁 activity 了。</p>
</blockquote>
<ul>
<li>在 Android Studio 的 Project Structure 中设置依赖项，即 Fragment 和 FragmentActivity</li>
</ul>
<blockquote>
<p>build.gradle 文件中依赖项字符串使用了 <a href="https://maven.apache.org/" target="_blank" rel="external">Maven</a> 坐标模式：groupId:artifactId:version。 groupId 是类库的基础包名，artifactId 是包中的特定库名，其中 *-vX 指所支持的最低 API 级别，比如 appcompat-v7 就是说此兼容库可以应用到 Android API 7 及以上级别的设备上。</p>
</blockquote>
<h1 id="2-fragment-的生命周期"><a href="#2-fragment-的生命周期" class="headerlink" title="2. fragment 的生命周期"></a>2. fragment 的生命周期</h1><p><img src="http://img.blog.csdn.net/20161026113629866" alt="fragment 的生命周期"></p>
<p>可以看出，fragment 的生命周期在许多地方对应着 activity 的生命周期方法，<strong>因为 fragment 的生命周期方法是由托管的 activity 调用的，而非像 activity 一样是由操作系统调用，fragment 仅仅是 activity 的内部事务</strong></p>
<blockquote>
<h3 id="fragment-的生命周期方法与-activity-的异同"><a href="#fragment-的生命周期方法与-activity-的异同" class="headerlink" title="fragment 的生命周期方法与 activity 的异同"></a><strong>fragment 的生命周期方法与 activity 的异同</strong></h3><ul>
<li><code>Fragment.onCreate(Bundle)</code> 是 public 的，而 <code>Activity.onCreate(Bundle)</code>则是 protected 的，因为前者是被 activity 调用，而后者是被系统调用。</li>
<li>fragment 仍然有类似的 <code>onSaveInstanceState(Bundle)</code> 函数用于保存状态</li>
<li>fragment 的视图建立不是在 <code>onCreate(…)</code> 中完成，而是在 <code>onCreateView(…)</code> 中完成（如下）。</li>
</ul>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> View <span class="title">onCreateView</span><span class="params">(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</span></span></div></pre></td></tr></table></figure>
<p>该方法实例化 fragment 视图的布局，然后将实例化的 View 返回给托管的 activity。 LayoutInflater 及 ViewGroup 是实例化布局的必要参数。Bundle 用来存储恢复数据，可供该方法从保存状态下重建视图。</p>
<h2 id="3-管理-fragment-的-FragmentManager-类"><a href="#3-管理-fragment-的-FragmentManager-类" class="headerlink" title="3. 管理 fragment 的 FragmentManager 类"></a>3. 管理 fragment 的 FragmentManager 类</h2><blockquote>
<p>activity 通过 FragmentManager 类管理 fragment 的队列和事务回退栈。</p>
</blockquote>
<h2 id="3-1-FragmentManager-的获取"><a href="#3-1-FragmentManager-的获取" class="headerlink" title="3.1 FragmentManager 的获取"></a>3.1 FragmentManager 的获取</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//使用 support 依赖包的情况下，用下面语句</span></div><div class="line">FragmentManager fm = getSupportFragmentManager();</div><div class="line"><span class="comment">//如果使用系统原生的 Fragment 类，即不考虑向后兼容时，使用：</span></div><div class="line">FragmentManager fm = getFragmentManager();</div></pre></td></tr></table></figure>
<h2 id="3-2-获取-fragment-并交由-FragmentManager-处理"><a href="#3-2-获取-fragment-并交由-FragmentManager-处理" class="headerlink" title="3.2 获取 fragment 并交由 FragmentManager 处理"></a>3.2 获取 fragment 并交由 FragmentManager 处理</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">Fragment fragment = fm.findFragmentById(R.id.fragment_container);</div><div class="line"></div><div class="line"><span class="keyword">if</span> (fragment == <span class="keyword">null</span>) &#123;</div><div class="line">	fragment = <span class="keyword">new</span> CrimeFragment();</div><div class="line">	<span class="comment">//下列代码创建、添加并提交了一个 fragment 事务</span></div><div class="line">	fm.beginTransaction()</div><div class="line">		.add(R.id.fragment_container, fragment)</div><div class="line">		.commit();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<blockquote>
<p>fragment 事务用来添加、移除、附加、分离或者替换 fragment 队列中的 fragment。 这是使用 fragment 在运行时组装和重新组装 UI 的关键。 Fragment Manager 管理着 fragment 事务回退栈。</p>
</blockquote>
<p>在上述代码中， FragmentManager.beginTransaction() 方法创建并返回 FragmentTransaction 实例，然后加入 FragmentTransaction 队列。add(…) 方法是整个事务的核心，它含有两个参数：容器视图资源 ID 和新创建的 CrimeFragment 。</p>
<p><strong>容器视图资源 ID 的作用是</strong>：</p>
<ul>
<li>告诉FragmentManager， fragment 视图应该出现在 activity 视图的什么位置。</li>
<li>用作 FragmentManager 队列中 fragment 的唯一标识符。</li>
</ul>
<p>如果要从 FragmentManager 中获取 CrimeFragment，直接使用容器视图资源 ID 即可（即上面代码的第一句）。初始时 FragmentManager 队列为空，故而需要下面的语句用于创建提交 fragment 至队列中，如果是恢复性地调用（如 activity 被销毁），则直接引用即可。</p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-20-cj0ajvow0002h1js6irpyb86g/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-20-cj0ajvow0002h1js6irpyb86g/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（六）—— 第6章 Android SDK 版本与兼容
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-20T17:17:10+08:00">
                2016-10-20
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-20-cj0ajvow0002h1js6irpyb86g/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-20-cj0ajvow0002h1js6irpyb86g/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>Android 开发的部分难度来源于系统版本的破碎分离。与 iOS 的极速占有不同，Android 手机的系统更新较慢，Android 的各大厂商各自为政，为了与友商形成差异化，对 AOSP 的修改各不相同；又因为产品线较多，开发难度增强，故而很多设备得不到更新的系统，有的只能依赖移植，大名鼎鼎的 CyanogenMod 的崛起即来源于此。</p>
<p>本章无代码</p>
</blockquote>
<p>问题就在于如何使自己的应用能够更多地兼容设备呢？</p>
<ul>
<li><p>选择最小的 SDK 版本时，应该选择份额较大的，比如 15~19</p>
</li>
<li><p>使用较新 API 带来的东西时，使用引入兼容库的方法，而非直接使用原生 API</p>
</li>
<li><p>在写代码时，如果不加以检查地直接使用minSdk版本不能使用的 API， Android Lint 会给出版本警告，此时不要忽略，尽量加入版本检查或者提高最低支持版本</p>
</li>
</ul>
<blockquote>
<p>直接在程序中查询设备的 SDK 版本，使用 <code>Build.VERSION.SDK_INT</code></p>
<p>Google 官方有一个 <a href="https://developer.android.com/about/dashboards/index.html" target="_blank" rel="external">Android 各版本份额实时报告</a> ，可以实时查看各版本所占比例</p>
</blockquote>
<p>下图是截至2016年10月20日，Android Studio 显示 Android 各 API 版本支持设备的比例：</p>
<p><img src="http://img.blog.csdn.net/20161020170131167" alt="Android 各 API 版本支持设备的比例"></p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-07-cj0ajvovx002e1js6cpnwwlvg/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-07-cj0ajvovx002e1js6cpnwwlvg/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（五）—— 第5章 第二个 Activity
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-07T11:49:10+08:00">
                2016-10-07
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-07-cj0ajvovx002e1js6cpnwwlvg/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-07-cj0ajvovx002e1js6cpnwwlvg/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要讲述了如何新建一个 Acitivity ，并在两个 Activity 之间传递数据，最后挑战练习是如何在重建 Activity 时保留数据。</p>
<p>GitHub 地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/0124102dcf27020a51341eaf48ac870b315e7bd4" target="_blank" rel="external">第五章未完成挑战</a><br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/2c1de49585be793c2395635bcc0ce55e40cd1ac9" target="_blank" rel="external">第五章完成挑战问题1，2</a><br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/1bf8869969409edd10ac1566446fb9a04a03dd2b" target="_blank" rel="external">第五章完成所有挑战问题</a></p>
</blockquote>
<h1 id="1-新建一个-Activity"><a href="#1-新建一个-Activity" class="headerlink" title="1. 新建一个 Activity"></a>1. 新建一个 Activity</h1><p>最好的方法是使用 Android Studio 自带的创建方法，若要手动创建，一定要有三个环环相扣的地方需要建立：</p>
<ul>
<li>一个 JAVA 类：即 Activity 类， 可以视需求继承 Activity 或者其他的衍生类</li>
<li>一个布局文件：对于任意一个 Activity 来说，都需要加载一个布局文件，在 res/layout 文件夹下新建一个布局文件，并在代码中使用 setContentView() 方法加载布局</li>
<li>★★★★★ <strong>一定要在 AndroidManifest.xml 中声明新的 Activity!</strong></li>
</ul>
<h1 id="2-启动Activity"><a href="#2-启动Activity" class="headerlink" title="2. 启动Activity"></a>2. 启动Activity</h1><p>Activity 类中的一个函数 <code>public void startActivity(Intent intent)</code>， 调用该方法时，启动 Activity 的请求直接发给了操作系统的 ActivityManager。ActivityManager 负责创建 Activity 实例并调用其 onCreate()方法。示意图如下：</p>
<p><img src="http://img.blog.csdn.net/20161021101552925" alt="基于 Intent 的交互"></p>
<blockquote>
<p>###基于Intent的通信<br>Intent 对象是 component 用来与操作系统通信的一种媒介工具。Intent 类提供了多种构造方法以满足不同的使用需求， 这章使用的就是最简单的启动一个新的 Activity 的构造方法。</p>
<p>component 就是四大组件：Activity, Service, Broadcast Receiver, Content Provider</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">Intent</span><span class="params">(Context packageContext, Class&lt;?&gt; cls)</span></span></div><div class="line"><span class="comment">//Class 对象必须已经在 AndroidManifest.xml 中声明才可以使用，否则将抛出 ActivityNotFoundException</span></div></pre></td></tr></table></figure>
<h1 id="3-Activity-间的数据传递"><a href="#3-Activity-间的数据传递" class="headerlink" title="3. Activity 间的数据传递"></a>3. Activity 间的数据传递</h1><h2 id="3-1-使用-Intent-Extra"><a href="#3-1-使用-Intent-Extra" class="headerlink" title="3.1 使用 Intent Extra"></a>3.1 使用 Intent Extra</h2><p>在使用 Intent 对象启动另一个 Activitiy 的时候使用了其构造方法，如果要让另一个 Activity 知道前一个 component 需要展示什么（比如用户到底点击了哪个按钮随之要展示什么详情），就需要在 Intent 中说明。使用 Intent 对象方法<code>public Intent putExtra(String name, &lt;Type&gt; data)</code> 将数据存到 Intent 对象内部，然后给操作系统。</p>
<p>这整个过程有点像送信：</p>
<ul>
<li>一个 component 应该先准备一个信封（Intent），在信封上写好发件人和收件人（显式 Intent 的构造方法）。</li>
<li>接着写信（Intent Extra），装到信封里（Intent），用 startActivity() 方法把信投递给操作系统的 ActivityManager。</li>
<li>ActivityManager 看到收件人的地址，去找到收件人，敲他家的门（调用其 onCreate() 方法），然后把信给他。</li>
</ul>
<p>这样，一个 Activity 就被启动了。</p>
<blockquote>
<p>一般来说，我们会在一个 Activity 中写入自己的启动方法或者一个『用于获取启动本 Activity 的 Intent 对象』的方法，因为这样的话，其他 component 在启动时能够清楚地知道需要什么参数。比如可以写一个 <code>public static void actionStart(Context, Extra)</code>函数，传入参数是本 Activity 的上下文，和需要传递的额外信息，这样别的 component 在启动时，只需要调用该静态方法即可。</p>
</blockquote>
<h2 id="3-2-从子-Activity-获取返回结果"><a href="#3-2-从子-Activity-获取返回结果" class="headerlink" title="3.2 从子 Activity 获取返回结果"></a>3.2 从子 Activity 获取返回结果</h2><p>还是用送信来类比，如果一封信被另一个 Activity 收到了，他拆了信看完以后就丢弃了，并不会回信。那么如果发信者想要收信者回信，需要先跟 ActivityManager 说好，而且还要约定一个暗号，以便回信时不会弄错，然后 ActivityManager 再投递信，敲门并告诉另一个 Activity 应该回信。</p>
<p>也就是说，如果启动另一个 Activity 并希望其在退出时返回结果，那么应该使用下面的方法，即先跟 ActivityManager 说好，暗号就是 requestCode 。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startActivityForResult</span><span class="params">(Intent intent, <span class="keyword">int</span> requestCode)</span></span></div><div class="line">``` </div><div class="line"></div><div class="line">自己也要做好准备接受消息，即重写方法 </div><div class="line"></div><div class="line">```java</div><div class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onActivityResult</span><span class="params">(<span class="keyword">int</span> requestCode, <span class="keyword">int</span> resultCode, Intent data)</span></div></pre></td></tr></table></figure>
<p>这个多出来的 resultCode 顾名思义，就是结果的正确与否，一般会使用 Activity.RESULT_OK 或者 Activity.RESULT_CANCELED 来标志， 或者自定义常量 Activity.RESULT_FIRST_USER 以便根据 Activity 返回结果来做出不同操作。如果下一个 Activity 不设置结果的话（也就是不回信），用户退出该 Activity 时会默认返回 RESULT_CANCELED。</p>
<p>而回信的人只需要写信即可，直接使用 Activity 的方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">setResult</span><span class="params">(<span class="keyword">int</span> requestCode, Intent data)</span></span></div><div class="line"><span class="comment">//或者</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">setResult</span><span class="params">(<span class="keyword">int</span> requestCode)</span></div></pre></td></tr></table></figure>
<p>回传的数据也是使用 Intent 封装的。</p>
<h2 id="3-3-最后大概总结一下这个过程："><a href="#3-3-最后大概总结一下这个过程：" class="headerlink" title="3.3 最后大概总结一下这个过程："></a>3.3 <strong>最后大概总结一下这个过程</strong>：</h2><ul>
<li><p>如果需要在启动另一个 Activity 时传递数据，就使用 Intent 的 putExtra() 方法</p>
</li>
<li><p>如果还需要返回结果，就要使用 startActivityForResult() 函数， 需要事先规定好 requestCode</p>
</li>
<li><p>同时父 Activity 需要重写 onActivityResult() 函数，对返回的结果进行处理</p>
</li>
<li><p>子 Activity 若要回传数据，调用 setResult() 方法将数据放入即可。</p>
</li>
</ul>
<blockquote>
<p>注： SharedPreferences 有时也能起到传递信息的作用，但是一般只用来保存基本类型的数据，所以作用有限，就像把东西放在一个共有的环境里，大家都知道那里有东西，谁需要都可以去取。</p>
</blockquote>
<h1 id="4-Activity-的使用与管理"><a href="#4-Activity-的使用与管理" class="headerlink" title="4.  Activity 的使用与管理"></a>4.  Activity 的使用与管理</h1><p>对于一个应用来说，启动时系统只是先启动了其中的一个 Activity，这个 Activity 理应已经在 AndroidManifest.xml 文件中声明为 Launcher Activity。</p>
<p>对于所有应用，其 Activity 共享同一个『回退栈』。如果没有重写 onBackPressed() 函数的话，按下返回键就将当前 Activity 弹出栈顶，或者自己调用了 Activity.finish() 函数时也同样会弹出栈顶。</p>
<h1 id="5-章末挑战"><a href="#5-章末挑战" class="headerlink" title="5. 章末挑战"></a>5. 章末挑战</h1><ol>
<li><p>用户作弊后，可以旋转 CheatActivity 来清除作弊痕迹。</p>
<blockquote>
<p>这个问题比较好处理，问题原因是由于旋转时需使用新的布局文件，重新调用了 onCreate() 方法，从而导致作弊痕迹丢失。那么重写 onSaveInstanceState() 方法，将其保存，在 onCreate() 中对数据进行恢复即可。</p>
</blockquote>
</li>
<li><p>作弊返回后， 用户可以旋转 QuizActivity 来清除 mIsCheater 变量值。</p>
<blockquote>
<p>同上</p>
</blockquote>
</li>
<li><p>用户可以不断单击NEXT按钮，跳到偷看过答案的问题，从而使作弊记录丢失。</p>
<blockquote>
<p>由于每道题有每道题的作弊记录，所以我的思路是采用一个 boolean 数组记录作弊情况，并且这个数组也应该在旋转的时候进行保存，在应用启动期间长期存在即可。如果有长期保存的需求，就要用到 SharedPreferences 或者数据库了。</p>
</blockquote>
</li>
</ol>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-07-cj0ajvovv002b1js6gazr2y8x/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-07-cj0ajvovv002b1js6gazr2y8x/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（四）—— 第4章 Android 应用的调试
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-07T11:48:10+08:00">
                2016-10-07
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-07-cj0ajvovv002b1js6gazr2y8x/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-07-cj0ajvovv002b1js6gazr2y8x/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要说明了如何调 bug，有 LogCat 法、Lint 法以及断点调试法。</p>
<p><del>本章无新增代码</del></p>
</blockquote>
<h1 id="1-LogCat-大法"><a href="#1-LogCat-大法" class="headerlink" title="1. LogCat 大法"></a>1. LogCat 大法</h1><p>将代码中的一句关联控件语句（即 findViewById() 语句）注释掉之后运行程序将会出现下列错误：</p>
<p><img src="http://img.blog.csdn.net/20161007160501236" alt="出现错误"></p>
<p>从图中可以看到是错误由 NullPointerException 引起，并且在 Caused… 那一行下方标明了具体出错的位置，此时如果下面出现自己的代码（如图中紫色字的 QuizActivity.java），基本上可以直接定位错误从而修改代码。其他的运行时错误也是用类似的方法修改。</p>
<p><strong>另外可以在关键的方法里写 Log，这样使用 Log filter 查看调试日志就会非常方便。</strong></p>
<h1 id="2-Android-Lint-大法"><a href="#2-Android-Lint-大法" class="headerlink" title="2. Android Lint 大法"></a>2. Android Lint 大法</h1><p>Android Lint 是 Android 应用代码的静态分析器(static analyzer)。它是无需代码运行就能够检查代码错误的特殊程序。凭着对Android框架知识的掌握，Android Lint 深入检查代码，找出编译器无法发现的问题。在大多数情况下，Android Lint 检查出的问题都值得关注。</p>
<p>Android Lint 还能够检查定义在 XML 文件中的对象类型与控件对象的匹配。如果使用了错误的资源 ID，代码运行时，会导致类型转换出现错误。显然，Java编译器无法检查到该错误，但Android Lint却可以捕获到该错误。</p>
<p>假如想主动查看项目中的所有潜在问题，可以选择Analyze → Inspect Code…菜单项手动运行 Lint。在被问及检查项目的哪部分时，选择Whole project。Android Studio 会立即运行 Lint 和其他 一些静态分析器开始分析代码。</p>
<p>检查完毕后,所有的潜在问题会按类别列出，展开Android Lint 类别即可看到项目的具体Lint信息。</p>
<h1 id="3-断点大法"><a href="#3-断点大法" class="headerlink" title="3. 断点大法"></a>3. 断点大法</h1><p>顾名思义……程序员基本素养，不赘述了。<br>补充一点，那就是在 debug 模式下可以直接把某个变量放到 WatchWindow 中进行实时观察，非常好用~</p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-06-cj0ajvovs00281js6drdpqa3q/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-06-cj0ajvovs00281js6drdpqa3q/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（三）—— 第3章 日志跟踪理解 Activity 生命周期
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-06T19:33:10+08:00">
                2016-10-06
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-06-cj0ajvovs00281js6drdpqa3q/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-06-cj0ajvovs00281js6drdpqa3q/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章主要讨论了 Activity 的生命周期，用 Log 工具来观察它，以及如何在设备配置改变时保存之前的状态</p>
<p>GitHub地址：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/d6a3dfd1e087e5484e6c7dc022f76799ac12cc7d" target="_blank" rel="external">GeoQuiz 第三章</a></p>
</blockquote>
<h1 id="1-Activity-的生命周期"><a href="#1-Activity-的生命周期" class="headerlink" title="1. Activity 的生命周期"></a>1. Activity 的生命周期</h1><p><img src="http://img.blog.csdn.net/20161007150307614" width="20%" alt="Activity 生命周期" align="center"></p>
<p>在设备运行中，设备配置（如屏幕方向、屏幕密度、屏幕尺寸、语言、键盘类型等）发生改变时，Android 需要自动完成最佳匹配资源的调用， 某些时候（如屏幕旋转时）它必须通过新建一个 Activity 来实现，所以需要重新调用 onCreate() 方法，从而设备配置改变前对 Activity 的更改将消失。</p>
<p><strong>如何在设备配置改变发生时保存数据，在之后返回到改变前的状态呢？</strong></p>
<p>就是通过复写 onSaveInstanceState() 方法保存需要保留的数据，代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onSaveInstanceState</span><span class="params">(Bundle outState)</span> </span>&#123;</div><div class="line">	<span class="keyword">super</span>.onSaveInstanceState(outState);</div><div class="line">	Log.i(TAG, <span class="string">"onSaveInstanceState"</span>);</div><div class="line">	outState.putInt(KEY_INDEX,mCurrentIndex);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>然后在 onCreate() 方法中加入对 savedInstanceState 这个 Bundle 变量的非空判定然后获取其中的数据对 Activity 的数据进行赋值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (savedInstanceState != <span class="keyword">null</span>）&#123;</div><div class="line">	mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, <span class="number">0</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>一个完整的包含暂存状态的 Acitvity 生命周期图示如下：</p>
<p><img src="http://img.blog.csdn.net/20161007153711019" width="40%" alt="完整的 Activity 生命周期"></p>
<h1 id="2-Log-工具"><a href="#2-Log-工具" class="headerlink" title="2. Log 工具"></a>2. Log 工具</h1><p>使用 Log 方式跟踪程序是一个比较好的习惯，而不是使用 <code>System.out.println()</code></p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-06-cj0ajvov9001e1js6yo6vbxva/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-06-cj0ajvov9001e1js6yo6vbxva/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（二）—— 第2章 Android 与 MVC 设计模式
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-06T17:53:00+08:00">
                2016-10-06
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-06-cj0ajvov9001e1js6yo6vbxva/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-06-cj0ajvov9001e1js6yo6vbxva/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>本章扩展了 GeoQuiz 程序，并介绍了 MVC 设计模式</p>
<p>GitHub 地址 ：<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/ac96c63ab29527f5e4e50764a7d6fa91800c3067" target="_blank" rel="external">GeoQuiz 第二章未完成挑战</a><br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/8e1d5c0d84cd013b655a671736c664409583a03c" target="_blank" rel="external">GeoQuiz 完成第二章所有挑战</a></p>
</blockquote>
<p>#1. MVC 设计模式<br>Android 应用基于模型-控制器-视图(Model - View - Controller, MVC)的架构模式进行设计。MVC 设计模式表明：应用的任何对象，归根结底都属于模型对象、视图对象以及控制对象中的一种。</p>
<ul>
<li><p><strong>模型对象存储着应用的数据和业务逻辑</strong>。<br>模型类通常用来映射与应用相关的一些事物，如 用户、商店里的商品、服务器上的图片或者一段电视节目；又或是 GeoQuiz 应用里的地理知识问题。<br>模型对象不关心用户界面，它存在的唯一目的就是存储和管理应用数据。<br><strong> Android 应用里的模型类通常就是我们创建的定制类。应用的全部模型对象组成了模型层。</strong></p>
</li>
<li><p><strong>视图对象知道如何在屏幕上绘制自己以及如何响应用户的输入，如用户的触摸等</strong>。<br>一个简单的经验法则是，凡是能够在屏幕上看见的对象，就是视图对象。Android 默认自带了很多可配置的视图类。当然，也可以定制开发自己的视图类。应用的 全部视图对象组成了视图层。 </p>
</li>
<li><p><strong>控制对象含有应用的逻辑单元，是视图与模型对象的联系纽带</strong>。<br>控制对象响应视图对象 触发的各类事件，此外还管理着模型对象与视图间的数据流动。 在 Android 的世界里，控制器通常是 Activity 、Fragment 或 Service 的一个子类。</p>
</li>
</ul>
<blockquote>
<p><img src="http://img.blog.csdn.net/20161007143005576" alt="MVC 模式图"></p>
<p>上图展示了在响应用户单击按钮等事件时，对象间的交互控制数据流。<em>注意，模型对象与 视图对象不直接交互。控制器作为它们之间的联系纽带，接收对象发送的消息，然后向其他对象发送操作指令。</em></p>
</blockquote>
<p>随着应用功能的持续扩展，应用往往会变得过于复杂而让人难以理解。把 Java 类以模型、视图和控制层进行分类组织，也有助于我们设计和理解应用。这样，我们就可以按层而非一个个类来考虑设计开发了。</p>
<p>使用 MVC 模式还可以让类的复用更加容易。相比功能多而全的类，功能单一的专用类更加有利于代码复用。</p>
<p>尽管 GeoQuiz 应用不复杂，但以 MVC 分层模式设计它的好处还是显而易见的。举例来说，模型类 Question 与用作显示问题的组件毫无代码逻辑关联。这样，就很容易在应用里按需使用 Question 类。假设现在想显示所有地理知识问题列表，很简单，直接复用 Question 对象逐条显示就可以了。</p>
<p>#2. 具体实现</p>
<ul>
<li>GeoQuiz 的模型层由 Question 类组成。</li>
<li>GeoQuiz 应用的视图层是由 activity_quiz.xml 文件中定义的各类组件构成的。</li>
<li>GeoQuiz 应用的控制层仅由 QuizActivity 类组成。</li>
</ul>
<p>构建模型层 Question 类，成员有文本的资源 ID 变量 mTextResId 和标记问题答案是否正确的 mAnswerTrue 变量。重写构造方法，添加了两个成员变量的 Getter 与 Setter 函数。</p>
<blockquote>
<p>Tip: <strong>如何在 Android Studio 中优雅地生成 Getter 和 Setter</strong><br>使用快捷键 Cmd + N</p>
</blockquote>
<ul>
<li>修改视图层，增加 Next 按钮。</li>
</ul>
<p>修改控制层，增加题目库 mQuestionBank 数组、 updateQuestion() 函数与 checkAnswer() 函数。并完成实现逻辑</p>
<p>添加箭头的图标资源放在 Next 按钮右侧。</p>
<p>#3. 挑战</p>
<p>本章挑战的难度较低，难点主要在于添加 Prev 按钮时要注意数组越界的问题。可以有以下几种实现：</p>
<ul>
<li>单独拎出越界的情况</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (mCurrentIndex == <span class="number">0</span>) &#123;</div><div class="line">	mCurrentIndex = mQuestionBank.length - <span class="number">1</span>;</div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">	mCurrentIndex = mCurrentIndex - <span class="number">1</span>;</div><div class="line">&#125;</div><div class="line">updateQuestion();</div></pre></td></tr></table></figure>
<ul>
<li>直接避免越界情况</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mCurrentIndex = (mCurrentIndex + mQuestionBank.length - <span class="number">1</span>) % mQuestionBank.length;</div></pre></td></tr></table></figure>
          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kniost.github.io/2016-10-06-cj0ajvouj000e1js6cfytutb8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kniost">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="结网之路">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016-10-06-cj0ajvouj000e1js6cfytutb8/" itemprop="url">
                  Android编程权威指南（第二版）学习笔记（一）——第1章 Android开发初体验
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-10-06T17:10:00+08:00">
                2016-10-06
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android编程权威指南学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Android编程权威指南学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016-10-06-cj0ajvouj000e1js6cfytutb8/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2016-10-06-cj0ajvouj000e1js6cfytutb8/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>此章是 Android 开发的基础内容，只有几个开发时的基本点需要注意</p>
<p>GitHub 链接:<br><a href="https://github.com/kniost/Android-Programming-Big-Nerd-Ranch-Guide-2nd/commit/5c5aed21dd8878fec7b2eb8c42ed72688c080a15" target="_blank" rel="external"> GeoQuiz 第1章</a></p>
</blockquote>
<h1 id="1-变量名命名规范"><a href="#1-变量名命名规范" class="headerlink" title="1. 变量名命名规范"></a>1. 变量名命名规范</h1><ul>
<li>建议子类名使用 Activity 后缀，如 QuizActivity.java</li>
<li>布局的命名规则是将 Activity 名称的单词顺序颠倒过来并全部转换为小写字母，然后在单词之间添加下划线，如 activity_quiz.xml</li>
<li><a href="http://www.cnblogs.com/wengfumin/articles/2337095.html" target="_blank" rel="external">包、类、变量、方法、数组等的命名规范</a></li>
</ul>
<h1 id="2-字符串资源"><a href="#2-字符串资源" class="headerlink" title="2. 字符串资源"></a>2. 字符串资源</h1><p>尽量使用字符串文件，而非写死字符串，以便于统一修改和语言版本转换</p>
<h1 id="3-Android-Studio-快捷键"><a href="#3-Android-Studio-快捷键" class="headerlink" title="3. Android Studio 快捷键"></a>3. Android Studio 快捷键</h1><ul>
<li>Option + Return (Alt + Enter) 组合键可以自动导入</li>
</ul>
<h1 id="4-引用组件"><a href="#4-引用组件" class="headerlink" title="4. 引用组件"></a>4. 引用组件</h1><p>引用组件使用以下方法，而且需要将返回的 View 对象转型（cast）为目标对象<br>示例如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mTrueButton = (Button) findViewById(R.id.true_button);</div></pre></td></tr></table></figure>
<h1 id="5-监听器的设置（使用匿名内部类）"><a href="#5-监听器的设置（使用匿名内部类）" class="headerlink" title="5. 监听器的设置（使用匿名内部类）"></a>5. 监听器的设置（使用匿名内部类）</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">mTrueButton.setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</div><div class="line">	<span class="meta">@Override</span></div><div class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>&#123;</div><div class="line">		<span class="comment">//Do whatever you want</span></div><div class="line">	&#125;</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<p>使用匿名内部类实现监听器有两个好处：代码更加清晰可读和避免不必要的命名类实现</p>
<h2 id="6-Android-编译过程"><a href="#6-Android-编译过程" class="headerlink" title="6.Android 编译过程"></a>6.Android 编译过程</h2><p> <img src="http://img.blog.csdn.net/20161007140508683" alt="Android 编译过程"></p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/2/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><a class="extend next" rel="next" href="/page/4/"><i class="fa fa-angle-right"></i></a>
  </nav>


          
          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      

      <section class="site-overview sidebar-panel sidebar-panel-active">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.jpg"
               alt="kniost" />
          <p class="site-author-name" itemprop="name">kniost</p>
           
              <p class="site-description motion-element" itemprop="description">kniost 的成长与疑惑</p>
          
        </div>
        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
              <a href="/archives">
                <span class="site-state-item-count">31</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/categories/index.html">
                <span class="site-state-item-count">3</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-tags">
              <a href="/tags/index.html">
                <span class="site-state-item-count">3</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" rel="alternate">
              <i class="fa fa-rss"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
        </div>

        
        

        
        

        


      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">kniost</span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Pisces
  </a>
</div>


        

        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    
    
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  




  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script>



  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script>



  



  

    <script type="text/javascript">
      var disqus_shortname = 'kniost-comment-github';
      var disqus_identifier = 'page/3/index.html';

      var disqus_title = "";


      function run_disqus_script(disqus_script) {
        var dsq = document.createElement('script');
        dsq.type = 'text/javascript';
        dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/' + disqus_script;
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
      }

      run_disqus_script('count.js');

      

    </script>
  










  
  

  

  

  

  


  

</body>
</html>
